﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using NHibernate;
using NHibernate.Linq;
using dbPoll_Application.Helpers;
using NHibernate.Criterion;
using dbPoll_Application.Controllers;

namespace dbPoll_Application.Models
{
    public class ParticipantRepository
    {
        public static Participant GetParticipantByParticipantID(int participantID)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            var participant = (from item in session.Query<Participant>()
                               where item.participantID == participantID
                               select item).FirstOrDefault<Participant>();
            return participant;
        }

        public static ParticipantGroup GetGroupByGroupID(int groupID)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            var group = (from item in session.Query<ParticipantGroup>()
                         where item.groupID == groupID
                         select item).FirstOrDefault<ParticipantGroup>();
            return group;
        }

        public static Participant GetParticipantByDeviceID(String deviceID)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            var participant = (from item in session.Query<Participant>()
                               where item.deviceID == deviceID
                               select item).FirstOrDefault<Participant>();
            return participant;
        }

        public static Participant GetParticipantByDeviceIDAndPoll(String deviceID, Poll poll)
        {
            var participant = poll.participants.FirstOrDefault(p=>p.deviceID.Equals(deviceID));
            return participant;
        }

        public static Participant GetParticipantByLinkedUser(User linkedUser)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            var participant = (from item in session.Query<Participant>()
                               where item.linkedUser.UserName == linkedUser.UserName
                               select item).FirstOrDefault<Participant>();
            return participant;
        }

        public static Participant GetParticipantByLinkedUserAndPoll(User linkedUser, Poll poll)
        {
            var participant = poll.participants.FirstOrDefault(p => p.linkedUser!=null && p.linkedUser.UserName.Equals(linkedUser.UserName));
            return participant;
        }

        public static IList<Participant> GetParticipantsByLinkedUser(User linkedUser)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            var participants = (from item in session.Query<Participant>()
                                where item.linkedUser.UserName == linkedUser.UserName
                                select item).ToList<Participant>();
            return participants;
        }

        public static ParticipantField GetParticipantFieldByID(int fieldID)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            var field = (from item in session.Query<ParticipantField>()
                         where item.fieldID == fieldID
                         select item).FirstOrDefault<ParticipantField>();
            return field;
        }

        public static ICollection<Dictionary<String, String>> GetGroupValuesByPollID(int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            IList<ParticipantGroup> groups = poll.groups;
            ICollection<Dictionary<String, String>> values = new HashSet<Dictionary<String, String>>();
            foreach (var group in groups)
            {
                values.Add(GetGroupDetailsByGroup(group, pollID));
            }
            return values;
        }

        public static Dictionary<String, String> GetGroupDetailsByGroup(ParticipantGroup groups, int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            Dictionary<String, String> groupd = new Dictionary<String, String>();
            groupd.Add("groupID", groups.groupID.ToString());
            groupd.Add("Name", groups.name);
            foreach (var field in poll.participantFields)
            {
                var q = (from p in field.fieldValues where (p.groupd != null && p.groupd.Equals(groups)) select p).ToList<ParticipantFieldValue>();
                if (q.Count() == 0) groupd.Add(field.name, "");
                else groupd.Add(field.name, q.ElementAt(0).value);
            }
            if (groups.entity != null) groupd.Add("Entity", groups.entity.name);
            else groupd.Add("Entity", "");
            return groupd;
        }

        public static ICollection<Dictionary<String, String>> GetParticipantValuesByPollID(int pollID)
        {
            Poll poll = PollRepository.GetPollByID(pollID);
            IList<Participant> participants = (from p in poll.participants orderby p.participantID select p).ToList<Participant>();
            ICollection<Dictionary<String, String>> values = new HashSet<Dictionary<String, String>>();
            foreach (var participant in participants)
            {
                values.Add(GetParticipantDetailsByParticipantID(participant.participantID, pollID));
            }
            return values;
        }

        public static Dictionary<String, String> GetParticipantDetailsByParticipantID(int participantID, int pollID)
        {
            Participant participant = GetParticipantByParticipantID(participantID);
            Poll poll = PollRepository.GetPollByID(pollID);
            Dictionary<String, String> partici = new Dictionary<String, String>();
            partici.Add("Participant ID", participant.participantID.ToString());
            partici.Add("Device ID", participant.deviceID.ToString());
            partici.Add("First Name", participant.firstName);
            partici.Add("Last Name", participant.lastName);
            foreach (var field in poll.participantFields)
            {
                var q = (from p in field.fieldValues where (p.participant != null && p.participant.Equals(participant)) select p).ToList<ParticipantFieldValue>();
                if (q.Count() == 0) partici.Add(field.name, "");
                else partici.Add(field.name, q.ElementAt(0).value);
            }
            if (participant.entity != null) partici.Add("Entity", participant.entity.name);
            else partici.Add("Entity", "");
            return partici;
        }

        public static Boolean UpdateFields(ParticipantField field)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.SaveOrUpdate(field);
                transaction.Commit();
                return transaction.WasCommitted;
            }
        }

        public static Boolean DeleteFields(ParticipantField field)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            var questions = (from item in session.Query<DemographicQuestion>()
                             where item.linkedField!=null && item.linkedField.fieldID == field.fieldID
                             select item).ToList();
            QuestionController p = new QuestionController();
            Poll poll;
            if (questions != null && questions.Count != 0)
            {
                poll = (from item in session.Query<Poll>()
                        where item.questions.Contains(questions.First())
                        select item).FirstOrDefault();
                foreach (DemographicQuestion q in questions)
                {
                    p.ConvertToCustom(q.questionID, poll.pollID);
                    if ((from item in session.Query<ParticipantField>()
                        where item.fieldID==field.fieldID select item).Count()==0)
                        return true;
                }
            }
            using (ITransaction transaction = session.BeginTransaction())
            {
                foreach (ParticipantFieldValue pv in field.fieldValues) { pv.participant = null; pv.groupd = null; }
                session.Delete(field);
                transaction.Commit();
                return transaction.WasCommitted;
            }
        }

        public static Boolean Delete(int participantID)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            using (ITransaction transaction = session.BeginTransaction())
            {
                var participant = (from item in session.Query<Participant>()
                                   where item.participantID == participantID
                                   select item).FirstOrDefault<Participant>();
                var questions = (from item in session.Query<Question>() 
                                 where item.responded.Any(p => p.participantID == participant.participantID) 
                                 select item).ToList();
                var response = (from item in session.Query<OptionResponse>()
                                where item.participant == participant
                                select item).ToList();
                var fields = (from item in session.Query<ParticipantFieldValue>()
                              where item.participant == participant
                              select item).ToList() ;
                var shortres = (from item in session.Query<ShortResponse>()
                                where item.participant == participant
                                select item).ToList();
                var feedback = (from item in session.Query<Feedback>() 
                                where item.providedBy == participant select item).ToList();
                foreach (var q in questions) q.responded.Remove(participant);
                foreach (var respond in response)
                {
                    QuestionOption option = (from item in session.Query<QuestionOption>()
                                             where item.responses.Any(r=>r.responseID==respond.responseID)
                                             select item).FirstOrDefault();
                    respond.participant = null;
                    option.responses.Remove(respond);
                }
                foreach (var respond in fields)
                {
                    ParticipantField option = (from item in session.Query<ParticipantField>()
                                               where item.fieldValues.Any(r=>r.fieldValueID==respond.fieldValueID)
                                               select item).FirstOrDefault();
                    respond.participant = null;
                    option.fieldValues.Remove(respond);
                }
                foreach (var respond in shortres)
                {
                    ShortResponseQuestion option = (from item in session.Query<ShortResponseQuestion>()
                                                    where item.responses.Any(r => r.responseID == respond.responseID)
                                                    select item).FirstOrDefault();
                    respond.participant = null;
                    option.responses.Remove(respond);
                }
                foreach (var respond in feedback)
                {
                    Question option = (from item in session.Query<ShortResponseQuestion>()
                                       where item.feedback.Any(r => r.feedbackID == respond.feedbackID)
                                                    select item).FirstOrDefault();
                    option.feedback.Remove(respond);
                    respond.providedBy = null;
                    session.Delete(respond);
                }
                participant.entity = null;
                participant.group = null;
                participant.linkedUser = null;
                session.Delete(participant);
                transaction.Commit();
                return transaction.WasCommitted;
            }
        }

        public static IList<Participant> GetTestParticipantsFromPoll(int pollID)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            var participants = from poll in session.Query<Poll>()
                               from participant in session.Query<Participant>()
                               where participant.isTestParticipant && poll.pollID == pollID
                               select participant;
            return participants.ToList<Participant>();
        }

        public static IList<Participant> GetParticipantsOfGroup(ParticipantGroup group, Poll poll)
        {
            List<Participant> participants = new List<Participant>();
            foreach (Participant participant in poll.participants)
            {
                if (participant.group == group) participants.Add(participant);
            }
            return participants;
        }

        public static Boolean Update(Participant p)
        {
            ITransaction transaction = null;
            try
            {
                ISession session = NHibernateHelper.GetCurrentSession();
                using (transaction = session.BeginTransaction())
                {
                    session.SaveOrUpdate(p);
                    transaction.Commit();
                    return transaction.WasCommitted;
                }
            }
            catch (Exception e)
            {
                if (transaction != null)
                {
                    transaction.Rollback();
                }
            }
            return false;
        }

        public static Boolean Update(ParticipantGroup p)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.SaveOrUpdate(p);
                transaction.Commit();
                return transaction.WasCommitted;
            }
        }

        public static ParticipantField GetFieldByID(int fieldID)
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            var field = from item in session.Query<ParticipantField>()
                        where item.fieldID == fieldID
                        select item;
            return field.FirstOrDefault<ParticipantField>();
        }

        public static int GetTotalParticipantCount()
        {
            ISession session = NHibernateHelper.GetCurrentSession();
            return session.Query<Participant>().Count<Participant>();
        }
    }
}
